#pragma once
#include <zCoreConfig.hpp>
#include <common.hpp>
#include "Tools.hpp"

namespace zzz{
inline bool StrCaseCmp(const string &str1, const string &str2) {
  int len1=str1.size();
  int len2=str2.size();
  int i1=0,i2=0;
  while(i1<len1 && i2<len2) {
    if (str1[i1]!=str2[i2])
      return false;
    i1++;
    i2++;
  }
  if (i1==len1 && i2==len2)
    return true;
  return false;
}

inline string RawToFormat_copy(const string &str) {
  zuint len=str.size();
  string ret;
  for (zuint i=0; i<len; i++) {
    if (str[i]=='\\') {
      if (i+1==len) break;
      i++;
      switch(str[i]) {
      case 'n':ret.push_back('\n');continue;
      case 'r':ret.push_back('\r');continue;
      case 't':ret.push_back('\t');continue;
      case 'b':ret.push_back('\b');continue;
      case '\\':ret.push_back('\\');continue;
      case '\"':ret.push_back('\"');continue;
      case '\'':ret.push_back('\'');continue;
      }
    }
    else ret.push_back(str[i]);
  }
  return ret;
}

inline void RawToFormat(string &str) {
  str=RawToFormat_copy(str);
}

inline void ToLow(char *str) {
  zuint len=strlen(str);
  for (zuint i=0; i<len; i++) {
    char x=str[i];
    if (x>='A' && x<='Z')
      str[i]=x+'a'-'A';
  }
}

inline void ToLow(string &str) {
  zuint len=str.size();
  for (zuint i=0; i<len; i++) {
    char x=str[i];
    if (x>='A' && x<='Z')
      str[i]=x+'a'-'A';
  }
}

inline string ToLow_copy(const string &str) {
  zuint len=str.size();
  string ret;
  for (zuint i=0; i<len; i++) {
    char x=str[i];
    if (x>='A' && x<='Z')
      ret.push_back(x+'a'-'A');
    else
      ret.push_back(x);
  }
  return ret;
}

ZCORE_FUNC string Replace(const string &ori, const string &from, const string &to);
////////////////////////////////////////
extern const string BlankChars;
ZCORE_FUNC string TrimFront(const string &str, const string &c=BlankChars);
ZCORE_FUNC string TrimBack(const string &str, const string &c=BlankChars);
ZCORE_FUNC string Trim(const string &str, const string &c=BlankChars);

ZCORE_FUNC void SplitString(const string &str, vector<string> &ret, const char splitchar=' ');
ZCORE_FUNC void JoinString(const vector<string> &strs, string &ret, const char joinchar=' ');
ZCORE_FUNC string JoinCmd(int argc, char *argv[]);

template <typename T>
void StringToVector(const string &str, vector<T> &ret) {
  T tmp;
  istringstream iss(str);
  ret.clear();
   while(true)
  {
    iss>>tmp;
    if (iss.fail()) return;
    ret.push_back(tmp);
  }
}

template<typename T>
void FromString(const string& str, T& v) {
  istringstream iss(str);
  iss>>v;
}

template<typename T>
void FromString(const string& str, std::vector<T>& v) {
  StringToVector(str, v);
}

template<>
inline void FromString(const string& str, bool &x) {
  string newstr = Trim(str);
  ToLow(newstr);
  if (newstr == "true" ||
      newstr == "t" ||
      newstr == ".t." ||
      newstr == "1")
    x = true;
  else
    x = false;
}

template<>
inline void FromString(const string& str, string &x) {
  x = str;
}

template<typename T>
T FromString(const string& str) {
  T ret;
  FromString(str, ret);
  return ret;
}

template<>
inline string FromString<string>(const string& str) {
  return str;
}

template<typename T>
void ToString(const T& val, string& str) {
  ostringstream oss;
  oss<<val;
  str=oss.str();
}

template<typename T>
string ToString(const T& val) {
  // DON'T CALL ToString(const T&, string&) which will make string copy three times
  ostringstream oss;
  oss<<val;
  return oss.str();
}

template<>
inline string ToString<bool>(const bool& var) {
  if (var)
    return "True";
  else
    return "False";
}

inline string operator<<(const string &strc, const string &add) {
  string str(strc);
  str+=add;
  return str;
}

inline string operator<<(const string &strc, const char *add) {
  string str(strc);
  str+=add;
  return str;
}

inline string& operator<<(string &str, const char *add) {
  str+=add;
  return str;
}

inline string& operator<<(string &str, const string &add) {
  str+=add;
  return str;
}


template<typename T>
string operator<<(const string &strc, const T &val) {
  string str(strc);
  ostringstream oss;
  oss<<val;
  str+=oss.str();
  return str;
}

template<typename T>
string& operator<<(string &str, const T &val) {
  ostringstream oss;
  oss<<val;
  str+=oss.str();
  return str;
}

inline bool StartsWith(const string &str, const string &pat) {
  if (str.size()<pat.size()) return false;
  return SafeEqual(pat.begin(), pat.end(), str.begin(), str.end());
}

ZCORE_FUNC string RandomString(int length, bool letters=true, bool numbers=true, bool symbols=false);
//BASE64 encode and decode
ZCORE_FUNC void Base64Encode(const string &data, const zsize size, string &code);
ZCORE_FUNC int Base64Decode(const string &code, char *data, const zsize size);
}
